<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>

<meta charset="utf-8">
<meta name="generator" content="quarto-1.7.33">

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">


<title>4&nbsp; Project 1 - Building a base64 encoder/decoder – Introduction to Zig</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
  width: 0.8em;
  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 
  vertical-align: middle;
}
/* CSS for syntax highlighting */
html { -webkit-text-size-adjust: 100%; }
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
  { counter-reset: source-line 0; }
pre.numberSource code > span
  { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
  { content: counter(source-line);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
  }
pre.numberSource { margin-left: 3em;  padding-left: 4px; }
div.sourceCode
  {   }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
/* CSS for citations */
div.csl-bib-body { }
div.csl-entry {
  clear: both;
  margin-bottom: 0em;
}
.hanging-indent div.csl-entry {
  margin-left:2em;
  text-indent:-2em;
}
div.csl-left-margin {
  min-width:2em;
  float:left;
}
div.csl-right-inline {
  margin-left:2em;
  padding-left:1em;
}
div.csl-indent {
  margin-left: 2em;
}</style>


<script src="../site_libs/quarto-nav/quarto-nav.js"></script>
<script src="../site_libs/quarto-nav/headroom.min.js"></script>
<script src="../site_libs/clipboard/clipboard.min.js"></script>
<script src="../site_libs/quarto-search/autocomplete.umd.js"></script>
<script src="../site_libs/quarto-search/fuse.min.js"></script>
<script src="../site_libs/quarto-search/quarto-search.js"></script>
<meta name="quarto:offset" content="../">
<link href="../Chapters/02-debugging.html" rel="next">
<link href="../Chapters/01-memory.html" rel="prev">
<script src="../site_libs/quarto-html/quarto.js" type="module"></script>
<script src="../site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
<script src="../site_libs/quarto-html/popper.min.js"></script>
<script src="../site_libs/quarto-html/tippy.umd.min.js"></script>
<script src="../site_libs/quarto-html/anchor.min.js"></script>
<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet">
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-59898bd1c6b9d2bb783127feaa000c76.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles">
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-dark-d329e753491efaeac79c98c4b193a686.css" rel="stylesheet" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles">
<link href="../site_libs/quarto-html/quarto-syntax-highlighting-59898bd1c6b9d2bb783127feaa000c76.css" rel="stylesheet" class="quarto-color-scheme-extra" id="quarto-text-highlighting-styles">
<script src="../site_libs/bootstrap/bootstrap.min.js"></script>
<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="../site_libs/bootstrap/bootstrap-5a7d69291c2a8c67bc3a157f4354e263.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light">
<link href="../site_libs/bootstrap/bootstrap-dark-a459d9a911ec262923466a12d18bc01e.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="dark">
<link href="../site_libs/bootstrap/bootstrap-5a7d69291c2a8c67bc3a157f4354e263.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme-extra" id="quarto-bootstrap" data-mode="light">
<script id="quarto-search-options" type="application/json">{
  "location": "sidebar",
  "copy-button": false,
  "collapse-after": 3,
  "panel-placement": "start",
  "type": "textbox",
  "limit": 50,
  "keyboard-shortcut": [
    "f",
    "/",
    "s"
  ],
  "show-item-context": false,
  "language": {
    "search-no-results-text": "No results",
    "search-matching-documents-text": "matching documents",
    "search-copy-link-title": "Copy link to search",
    "search-hide-matches-text": "Hide additional matches",
    "search-more-match-text": "more match in this document",
    "search-more-matches-text": "more matches in this document",
    "search-clear-button-title": "Clear",
    "search-text-placeholder": "",
    "search-detached-cancel-button-title": "Cancel",
    "search-submit-button-title": "Submit",
    "search-label": "Search"
  }
}</script>
<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-6CHJXK4CEV"></script>

<script type="text/javascript">

window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-6CHJXK4CEV', { 'anonymize_ip': true});
</script>

  <script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
  <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>

<script type="text/javascript">
const typesetMath = (el) => {
  if (window.MathJax) {
    // MathJax Typeset
    window.MathJax.typeset([el]);
  } else if (window.katex) {
    // KaTeX Render
    var mathElements = el.getElementsByClassName("math");
    var macros = [];
    for (var i = 0; i < mathElements.length; i++) {
      var texText = mathElements[i].firstChild;
      if (mathElements[i].tagName == "SPAN") {
        window.katex.render(texText.data, mathElements[i], {
          displayMode: mathElements[i].classList.contains('display'),
          throwOnError: false,
          macros: macros,
          fleqn: false
        });
      }
    }
  }
}
window.Quarto = {
  typesetMath
};
</script>

</head>

<body class="nav-sidebar floating quarto-light"><script id="quarto-html-before-body" type="application/javascript">
    const toggleBodyColorMode = (bsSheetEl) => {
      const mode = bsSheetEl.getAttribute("data-mode");
      const bodyEl = window.document.querySelector("body");
      if (mode === "dark") {
        bodyEl.classList.add("quarto-dark");
        bodyEl.classList.remove("quarto-light");
      } else {
        bodyEl.classList.add("quarto-light");
        bodyEl.classList.remove("quarto-dark");
      }
    }
    const toggleBodyColorPrimary = () => {
      const bsSheetEl = window.document.querySelector("link#quarto-bootstrap:not([rel=disabled-stylesheet])");
      if (bsSheetEl) {
        toggleBodyColorMode(bsSheetEl);
      }
    }
    const setColorSchemeToggle = (alternate) => {
      const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle');
      for (let i=0; i < toggles.length; i++) {
        const toggle = toggles[i];
        if (toggle) {
          if (alternate) {
            toggle.classList.add("alternate");
          } else {
            toggle.classList.remove("alternate");
          }
        }
      }
    };
    const toggleColorMode = (alternate) => {
      // Switch the stylesheets
      const primaryStylesheets = window.document.querySelectorAll('link.quarto-color-scheme:not(.quarto-color-alternate)');
      const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate');
      manageTransitions('#quarto-margin-sidebar .nav-link', false);
      if (alternate) {
        // note: dark is layered on light, we don't disable primary!
        enableStylesheet(alternateStylesheets);
        for (const sheetNode of alternateStylesheets) {
          if (sheetNode.id === "quarto-bootstrap") {
            toggleBodyColorMode(sheetNode);
          }
        }
      } else {
        disableStylesheet(alternateStylesheets);
        enableStylesheet(primaryStylesheets)
        toggleBodyColorPrimary();
      }
      manageTransitions('#quarto-margin-sidebar .nav-link', true);
      // Switch the toggles
      setColorSchemeToggle(alternate)
      // Hack to workaround the fact that safari doesn't
      // properly recolor the scrollbar when toggling (#1455)
      if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) {
        manageTransitions("body", false);
        window.scrollTo(0, 1);
        setTimeout(() => {
          window.scrollTo(0, 0);
          manageTransitions("body", true);
        }, 40);
      }
    }
    const disableStylesheet = (stylesheets) => {
      for (let i=0; i < stylesheets.length; i++) {
        const stylesheet = stylesheets[i];
        stylesheet.rel = 'disabled-stylesheet';
      }
    }
    const enableStylesheet = (stylesheets) => {
      for (let i=0; i < stylesheets.length; i++) {
        const stylesheet = stylesheets[i];
        if(stylesheet.rel !== 'stylesheet') { // for Chrome, which will still FOUC without this check
          stylesheet.rel = 'stylesheet';
        }
      }
    }
    const manageTransitions = (selector, allowTransitions) => {
      const els = window.document.querySelectorAll(selector);
      for (let i=0; i < els.length; i++) {
        const el = els[i];
        if (allowTransitions) {
          el.classList.remove('notransition');
        } else {
          el.classList.add('notransition');
        }
      }
    }
    const isFileUrl = () => {
      return window.location.protocol === 'file:';
    }
    const hasAlternateSentinel = () => {
      let styleSentinel = getColorSchemeSentinel();
      if (styleSentinel !== null) {
        return styleSentinel === "alternate";
      } else {
        return false;
      }
    }
    const setStyleSentinel = (alternate) => {
      const value = alternate ? "alternate" : "default";
      if (!isFileUrl()) {
        window.localStorage.setItem("quarto-color-scheme", value);
      } else {
        localAlternateSentinel = value;
      }
    }
    const getColorSchemeSentinel = () => {
      if (!isFileUrl()) {
        const storageValue = window.localStorage.getItem("quarto-color-scheme");
        return storageValue != null ? storageValue : localAlternateSentinel;
      } else {
        return localAlternateSentinel;
      }
    }
    const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => {
      const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light';
      const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark';
      let newTheme = '';
      if(authorPrefersDark) {
        newTheme = isAlternate ? baseTheme : alternateTheme;
      } else {
        newTheme = isAlternate ? alternateTheme : baseTheme;
      }
      const changeGiscusTheme = () => {
        // From: https://github.com/giscus/giscus/issues/336
        const sendMessage = (message) => {
          const iframe = document.querySelector('iframe.giscus-frame');
          if (!iframe) return;
          iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
        }
        sendMessage({
          setConfig: {
            theme: newTheme
          }
        });
      }
      const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null;
      if (isGiscussLoaded) {
        changeGiscusTheme();
      }
    };
    const authorPrefersDark = false;
    const darkModeDefault = authorPrefersDark;
      document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet';
      document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet';
    let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default';
    // Dark / light mode switch
    window.quartoToggleColorScheme = () => {
      // Read the current dark / light value
      let toAlternate = !hasAlternateSentinel();
      toggleColorMode(toAlternate);
      setStyleSentinel(toAlternate);
      toggleGiscusIfUsed(toAlternate, darkModeDefault);
      window.dispatchEvent(new Event('resize'));
    };
    // Switch to dark mode if need be
    if (hasAlternateSentinel()) {
      toggleColorMode(true);
    } else {
      toggleColorMode(false);
    }
  </script>

<div id="quarto-search-results"></div>
  <header id="quarto-header" class="headroom fixed-top">
  <nav class="quarto-secondary-nav">
    <div class="container-fluid d-flex">
      <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
        <i class="bi bi-layout-text-sidebar-reverse"></i>
      </button>
        <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../Chapters/01-base64.html"><span class="chapter-number">4</span>&nbsp; <span class="chapter-title">Project 1 - Building a base64 encoder/decoder</span></a></li></ol></nav>
        <a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">      
        </a>
      <button type="button" class="btn quarto-search-button" aria-label="Search" onclick="window.quartoOpenSearch();">
        <i class="bi bi-search"></i>
      </button>
    </div>
  </nav>
</header>
<!-- content -->
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article">
<!-- sidebar -->
  <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation floating overflow-auto">
    <div class="pt-lg-2 mt-2 text-left sidebar-header">
    <div class="sidebar-title mb-0 py-0">
      <a href="../">Introduction to Zig</a> 
        <div class="sidebar-tools-main">
  <a href="" class="quarto-color-scheme-toggle quarto-navigation-tool  px-1" onclick="window.quartoToggleColorScheme(); return false;" title="Toggle dark mode"><i class="bi"></i></a>
</div>
    </div>
      </div>
        <div class="mt-2 flex-shrink-0 align-items-center">
        <div class="sidebar-search">
        <div id="quarto-search" class="" title="Search"></div>
        </div>
        </div>
    <div class="sidebar-menu-container"> 
    <ul class="list-unstyled mt-1">
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../index.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text">Welcome</span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/01-zig-weird.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">1</span>&nbsp; <span class="chapter-title">Introducing Zig</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/03-structs.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">2</span>&nbsp; <span class="chapter-title">Control flow, structs, modules and types</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/01-memory.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">3</span>&nbsp; <span class="chapter-title">Memory and Allocators</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/01-base64.html" class="sidebar-item-text sidebar-link active">
 <span class="menu-text"><span class="chapter-number">4</span>&nbsp; <span class="chapter-title">Project 1 - Building a base64 encoder/decoder</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/02-debugging.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">5</span>&nbsp; <span class="chapter-title">Debugging Zig applications</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/05-pointers.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">6</span>&nbsp; <span class="chapter-title">Pointers and Optionals</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/04-http-server.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">7</span>&nbsp; <span class="chapter-title">Project 2 - Building a HTTP Server from scratch</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/03-unittests.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">8</span>&nbsp; <span class="chapter-title">Unit tests</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/07-build-system.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">9</span>&nbsp; <span class="chapter-title">Build System</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/09-error-handling.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">10</span>&nbsp; <span class="chapter-title">Error handling and unions</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/09-data-structures.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">11</span>&nbsp; <span class="chapter-title">Data Structures</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/10-stack-project.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">12</span>&nbsp; <span class="chapter-title">Project 3 - Building a stack data structure</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/12-file-op.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">13</span>&nbsp; <span class="chapter-title">Filesystem and Input/Output (IO)</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/14-zig-c-interop.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">14</span>&nbsp; <span class="chapter-title">Zig interoperability with C</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/13-image-filter.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">15</span>&nbsp; <span class="chapter-title">Project 4 - Developing an image filter</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/14-threads.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">16</span>&nbsp; <span class="chapter-title">Introducing threads and parallelism in Zig</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/15-vectors.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text"><span class="chapter-number">17</span>&nbsp; <span class="chapter-title">Introducing Vectors and SIMD</span></span></a>
  </div>
</li>
        <li class="sidebar-item">
  <div class="sidebar-item-container"> 
  <a href="../Chapters/references.html" class="sidebar-item-text sidebar-link">
 <span class="menu-text">References</span></a>
  </div>
</li>
    </ul>
    </div>
</nav>
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
<!-- margin-sidebar -->
    <div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
        <nav id="TOC" role="doc-toc" class="toc-active">
    <h2 id="toc-title">Table of contents</h2>
   
  <ul>
  <li><a href="#how-the-base64-algorithm-work" id="toc-how-the-base64-algorithm-work" class="nav-link active" data-scroll-target="#how-the-base64-algorithm-work"><span class="header-section-number">4.1</span> How the base64 algorithm work?</a>
  <ul class="collapse">
  <li><a href="#sec-base64-scale" id="toc-sec-base64-scale" class="nav-link" data-scroll-target="#sec-base64-scale"><span class="header-section-number">4.1.1</span> The base64 scale</a></li>
  <li><a href="#sec-base64-table" id="toc-sec-base64-table" class="nav-link" data-scroll-target="#sec-base64-table"><span class="header-section-number">4.1.2</span> Creating the scale as a lookup table</a></li>
  <li><a href="#sec-base64-encoder-algo" id="toc-sec-base64-encoder-algo" class="nav-link" data-scroll-target="#sec-base64-encoder-algo"><span class="header-section-number">4.1.3</span> A base64 encoder</a></li>
  <li><a href="#sec-base64-decoder-algo" id="toc-sec-base64-decoder-algo" class="nav-link" data-scroll-target="#sec-base64-decoder-algo"><span class="header-section-number">4.1.4</span> A base64 decoder</a></li>
  </ul></li>
  <li><a href="#sec-encode-vs-decode" id="toc-sec-encode-vs-decode" class="nav-link" data-scroll-target="#sec-encode-vs-decode"><span class="header-section-number">4.2</span> Difference between encode and decode</a></li>
  <li><a href="#sec-base64-length-out" id="toc-sec-base64-length-out" class="nav-link" data-scroll-target="#sec-base64-length-out"><span class="header-section-number">4.3</span> Calculating the size of the output</a></li>
  <li><a href="#sec-encoder-logic" id="toc-sec-encoder-logic" class="nav-link" data-scroll-target="#sec-encoder-logic"><span class="header-section-number">4.4</span> Building the encoder logic</a>
  <ul class="collapse">
  <li><a href="#sec-6bit-transf" id="toc-sec-6bit-transf" class="nav-link" data-scroll-target="#sec-6bit-transf"><span class="header-section-number">4.4.1</span> The 6-bit transformation</a></li>
  <li><a href="#bit-shifting-in-zig" id="toc-bit-shifting-in-zig" class="nav-link" data-scroll-target="#bit-shifting-in-zig"><span class="header-section-number">4.4.2</span> Bit-shifting in Zig</a></li>
  <li><a href="#selecting-specific-bits-with-the-operator" id="toc-selecting-specific-bits-with-the-operator" class="nav-link" data-scroll-target="#selecting-specific-bits-with-the-operator"><span class="header-section-number">4.4.3</span> Selecting specific bits with the <code>&amp;</code> operator</a></li>
  <li><a href="#allocating-space-for-the-output" id="toc-allocating-space-for-the-output" class="nav-link" data-scroll-target="#allocating-space-for-the-output"><span class="header-section-number">4.4.4</span> Allocating space for the output</a></li>
  <li><a href="#writing-the-encode-function" id="toc-writing-the-encode-function" class="nav-link" data-scroll-target="#writing-the-encode-function"><span class="header-section-number">4.4.5</span> Writing the <code>encode()</code> function</a></li>
  </ul></li>
  <li><a href="#sec-decoder-logic" id="toc-sec-decoder-logic" class="nav-link" data-scroll-target="#sec-decoder-logic"><span class="header-section-number">4.5</span> Building the decoder logic</a>
  <ul class="collapse">
  <li><a href="#sec-map-base64-index" id="toc-sec-map-base64-index" class="nav-link" data-scroll-target="#sec-map-base64-index"><span class="header-section-number">4.5.1</span> Mapping base64 characters to their indexes</a></li>
  <li><a href="#the-6-bit-transformation" id="toc-the-6-bit-transformation" class="nav-link" data-scroll-target="#the-6-bit-transformation"><span class="header-section-number">4.5.2</span> The 6-bit transformation</a></li>
  <li><a href="#writing-the-decode-function" id="toc-writing-the-decode-function" class="nav-link" data-scroll-target="#writing-the-decode-function"><span class="header-section-number">4.5.3</span> Writing the <code>decode()</code> function</a></li>
  </ul></li>
  <li><a href="#the-end-result" id="toc-the-end-result" class="nav-link" data-scroll-target="#the-end-result"><span class="header-section-number">4.6</span> The end result</a></li>
  </ul>
</nav>
    </div>
<!-- main -->
<main class="content" id="quarto-document-content">


<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<h1 class="title"><span id="sec-base64" class="quarto-section-identifier"><span class="chapter-number">4</span>&nbsp; <span class="chapter-title">Project 1 - Building a base64 encoder/decoder</span></span></h1>
</div>



<div class="quarto-title-meta">

    
  
    
  </div>
  


</header>


<p>As our first small project, I want to implement a base64 encoder/decoder with you. Base64 is an encoding system which translates binary data to text. A big chunk of the web uses base64 to deliver binary data to systems that can only read text data.</p>
<p>The most common example of a modern use case for base64 is essentially any email system, like GMail, Outlook, etc. Because email systems normally use the Simple Mail Transfer Protocol (SMTP), which is a web protocol that supports only text data. So, if you need, for any reason, to send a binary file (like for example, a PDF, or an Excel file) as an attachment in your email, these binary files are normally converted to base64, before they are included in the SMTP message. So, the base64 encoding is largely used in these email systems to include binary data into the SMTP message.</p>
<section id="how-the-base64-algorithm-work" class="level2" data-number="4.1">
<h2 data-number="4.1" class="anchored" data-anchor-id="how-the-base64-algorithm-work"><span class="header-section-number">4.1</span> How the base64 algorithm work?</h2>
<p>But how exactly does the algorithm behind the base64 encoding work? Let’s discuss that. First, I will explain the base64 scale, which is the 64-character scale that is the basis for the base64 encoding system.</p>
<p>After that, I explain the algorithm behind a base64 encoder, which is the part of the algorithm that is responsible for encoding messages into the base64 encoding system. Then, after that, I explain the algorithm behind a base64 decoder, which is the part of the algorithm that is responsible for translating base64 messages back into their original meaning.</p>
<p>If you are unsure about the differences between an “encoder” and a “decoder”, take a look at <a href="#sec-encode-vs-decode" class="quarto-xref"><span>Section 4.2</span></a>.</p>
<section id="sec-base64-scale" class="level3" data-number="4.1.1">
<h3 data-number="4.1.1" class="anchored" data-anchor-id="sec-base64-scale"><span class="header-section-number">4.1.1</span> The base64 scale</h3>
<p>The base64 encoding system is based on a scale that goes from 0 to 63 (hence the name). Each index in this scale is represented by a character (it’s a scale of 64 characters). So, in order to convert some binary data, to the base64 encoding, we need to convert each binary number to the corresponding character in this “scale of 64 characters”.</p>
<p>The base64 scale starts with all ASCII uppercase letters (A to Z) which represents the first 25 indexes in this scale (0 to 25). After that, we have all ASCII lowercase letters (a to z), which represents the range 26 to 51 in the scale. After that, we have the one digit numbers (0 to 9), which represents the indexes from 52 to 61 in the scale. Finally, the last two indexes in the scale (62 and 63) are represented by the characters <code>+</code> and <code>/</code>, respectively.</p>
<p>These are the 64 characters that compose the base64 scale. The equal sign character (<code>=</code>) is not part of the scale itself, but it is a special character in the base64 encoding system. This character is used solely as a suffix, to mark the end of the character sequence, or, to mark the end of meaningful characters in the sequence.</p>
<p>The bullet points below summarises the base64 scale:</p>
<ul>
<li>range 0 to 25 is represented by: ASCII uppercase letters <code>-&gt; [A-Z]</code>;</li>
<li>range 26 to 51 is represented by: ASCII lowercase letters <code>-&gt; [a-z]</code>;</li>
<li>range 52 to 61 is represented by: one digit numbers <code>-&gt; [0-9]</code>;</li>
<li>index 62 and 63 are represented by the characters <code>+</code> and <code>/</code>, respectively;</li>
<li>the character <code>=</code> represents the end of meaningful characters in the sequence;</li>
</ul>
</section>
<section id="sec-base64-table" class="level3" data-number="4.1.2">
<h3 data-number="4.1.2" class="anchored" data-anchor-id="sec-base64-table"><span class="header-section-number">4.1.2</span> Creating the scale as a lookup table</h3>
<p>The best way to represent this scale in code, is to represent it as a <em>lookup table</em>. Lookup tables are a classic strategy in computer science to speed up calculations. The basic idea is to replace a runtime calculation (which can take a long time to be done) with a basic array indexing operation.</p>
<p>Instead of calculating the results everytime you need them, you calculate all possible results at once, and then, you store them in an array (which behaves like a “table”). Then, every time you need to use one of the characters in the base64 scale, instead of using many resources to calculate the exact character to be used, you simply retrieve this character from the array where you stored all the possible characters in the base64 scale. We retrieve the character that we need directly from memory.</p>
<p>We can start building a Zig struct to store our base64 decoder/encoder logic. We start with the <code>Base64</code> struct below. For now, we only have one single data member in this struct, i.e., the member <code>_table</code>, which represents our lookup table. We also have an <code>init()</code> method, to create a new instance of a <code>Base64</code> object, and, a <code>_char_at()</code> method, which is a “get character at index <span class="math inline">\(x\)</span>” type of function.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> Base64 = <span class="kw">struct</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    _table: *<span class="kw">const</span> [<span class="dv">64</span>]<span class="dt">u8</span>,</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> init() Base64 <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="kw">const</span> upper = <span class="st">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">const</span> lower = <span class="st">"abcdefghijklmnopqrstuvwxyz"</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        <span class="kw">const</span> numbers_symb = <span class="st">"0123456789+/"</span>;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> Base64<span class="op">{</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>            ._table = upper ++ lower ++ numbers_symb,</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> _char_at(self: Base64, index: <span class="dt">usize</span>) <span class="dt">u8</span> <span class="op">{</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> self._table[index];</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p>In other words, the <code>_char_at()</code> method is responsible for getting the character in the lookup table (i.e., the <code>_table</code> struct data member) that corresponds to a particular index in the “base64 scale”. So, in the example below, we know that the character that corresponds to the index 28 in the “base64 scale” is the character “c”.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> base64 = Base64.init();</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">try</span> stdout.print(</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="st">"Character at index 28: {c}</span><span class="sc">\n</span><span class="st">"</span>,</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    .<span class="op">{</span>base64._char_at(<span class="dv">28</span>)<span class="op">}</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">try</span> stdout.flush();</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<pre><code>Character at index 28: c</code></pre>
</section>
<section id="sec-base64-encoder-algo" class="level3" data-number="4.1.3">
<h3 data-number="4.1.3" class="anchored" data-anchor-id="sec-base64-encoder-algo"><span class="header-section-number">4.1.3</span> A base64 encoder</h3>
<p>The algorithm behind a base64 encoder usually works on a window of 3 bytes. Because each byte has 8 bits, so, 3 bytes forms a set of <span class="math inline">\(8 \times 3 = 24\)</span> bits. This is desirable for the base64 algorithm, because 24 bits is divisible by 6, which forms <span class="math inline">\(24 / 6 = 4\)</span> groups of 6 bits each.</p>
<p>Therefore, the base64 algorithm works by converting 3 bytes at a time into 4 characters from the base64 scale. It keeps iterating through the input string, 3 bytes at a time, and converting them into the base64 scale, producing 4 characters per iteration. It keeps iterating, and producing these “new characters” until it hits the end of the input string.</p>
<p>Now you may think, what if you have a particular string that has a number of bytes that is not divisible by 3 - what happens? For example, if you have a string that contains only two characters/bytes, such as “Hi”. How would the algorithm behave in such situation? You find the answer in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a>. You can see in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a> that the string “Hi”, when converted to base64, becomes the string “SGk=”:</p>
<div id="fig-base64-algo1" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-base64-algo1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="./../Figures/base64-encoder-flow.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-base64-algo1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4.1: The logic behind a base64 encoder
</figcaption>
</figure>
</div>
<p>Taking the string “Hi” as an example, we have 2 bytes, or, 16 bits in total. So, we lack a full byte (8 bits) to complete the window of 24 bits that the base64 algorithm likes to work on. The first thing that the algorithm does, is to check how to divide the input bytes into groups of 6 bits.</p>
<p>If the algorithm notices that there is a group of 6 bits that it’s not complete, meaning that, this group contains <span class="math inline">\(nbits\)</span>, where <span class="math inline">\(0 &lt; nbits &lt; 6\)</span>, the algorithm simply adds extra zeros in this group to fill the space that it needs. That is why in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a>, in the third group after the 6-bit transformation, 2 extra zeros were added to fill the gap.</p>
<p>When we have a 6-bit group that is not completely full, like the third group, extra zeros are added to fill the gap. But what about when an entire 6-bit group is empty, or, it simply doesn’t exist? This is the case of the fourth 6-bit group exposed at <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a>.</p>
<p>This fourth group is necessary, because the algorithm works on 4 groups of 6 bits. But the input string does not have enough bytes to create a fourth 6-bit group. Every time this happens, where an entire group of 6 bits is empty, this group becomes a “padding group”. Every “padding group” is mapped to the character <code>=</code> (equal sign), which represents “null”, or, the end of meaningful characters in the sequence. Hence, everytime that the algorithm produces a “padding group”, this group is automatically mapped to <code>=</code>.</p>
<p>As another example, if you give the string “0” as input to a base64 encoder, this string is translated into the base64 sequence “MA==”. The character “0” is, in binary, the sequence <code>00110000</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>. So, with the 6-bit transformation exposed in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a>, this single character would produce these two 6-bit groups: <code>001100</code>, <code>000000</code>. The remaining two 6-bit groups become “padding groups”. That is why the last two characters in the output sequence (MA==) are <code>==</code>.</p>
</section>
<section id="sec-base64-decoder-algo" class="level3" data-number="4.1.4">
<h3 data-number="4.1.4" class="anchored" data-anchor-id="sec-base64-decoder-algo"><span class="header-section-number">4.1.4</span> A base64 decoder</h3>
<p>The algorithm behind a base64 decoder is essentially the inverse process of a base64 encoder. A base64 decoder needs to translate base64 messages back into their original meaning, i.e., into the original sequence of binary data.</p>
<p>A base64 decoder usually works on a window of 4 bytes. Because it wants to convert these 4 bytes back into the original sequence of 3 bytes, that was converted into 4 groups of 6 bits by the base64 encoder. Remember, in a base64 decoder we are essentially reverting the process made by the base64 encoder.</p>
<p>Each byte in the input string (the base64 encoded string) normally contributes to re-create two different bytes in the output (the original binary data). In other words, each byte that comes out of a base64 decoder is created by transforming merging two different bytes in the input together. You can visualize this relationship in <a href="#fig-base64-algo2" class="quarto-xref">Figure&nbsp;<span>4.2</span></a>:</p>
<div id="fig-base64-algo2" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-base64-algo2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="./../Figures/base64-decoder-flow.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-base64-algo2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4.2: The logic behind a base64 decoder
</figcaption>
</figure>
</div>
<p>The exact transformations, or, the exact steps applied to each byte from the input to transform them into the bytes of the output, are a bit tricky to visualize in a figure like this. Because of that, I have summarized these transformations as “Some bit shifting and additions …” in the figure. These transformations will be described in depth later.</p>
<p>Besides that, if you look again in <a href="#fig-base64-algo2" class="quarto-xref">Figure&nbsp;<span>4.2</span></a>, you will notice that the character <code>=</code> was completely ignored by the algorithm. Remember, this is just a special character that marks the end of meaningful characters in the base64 sequence. So, every <code>=</code> character in a base64 encoded sequence should be ignored by a base64 decoder.</p>
</section>
</section>
<section id="sec-encode-vs-decode" class="level2" data-number="4.2">
<h2 data-number="4.2" class="anchored" data-anchor-id="sec-encode-vs-decode"><span class="header-section-number">4.2</span> Difference between encode and decode</h2>
<p>If you don’t have any previous experience with base64, you might not understand the differences between “encode” and “decode”. Essentially, the terms “encode” and “decode” here have the exact same meaning as they have in the field of encryption (i.e., they mean the same thing as “encode” and “decode” in hashing algorithms, like the MD5 algorithm).</p>
<p>Thus, “encode” means that we want to encode, or, in other words, we want to translate some message into the base64 encoding system. We want to produce the sequence of base64 characters that represent this original message in the base64 encoding system.</p>
<p>In contrast, “decode” represents the inverse process. We want to decode, or, in other words, translate a base64 message back to its original content. So, in this process we get a sequence of base64 characters as input, and produce as output, the binary data that is represented by this sequence of base64 characters.</p>
<p>Any base64 library is normally composed of these two parts: 1) the encoder, which is a function that encodes (i.e., it converts) any sequence of binary data into a sequence of base64 characters; 2) the decoder, which is a function that converts a sequence of base64 characters back into the original sequence of binary data.</p>
</section>
<section id="sec-base64-length-out" class="level2" data-number="4.3">
<h2 data-number="4.3" class="anchored" data-anchor-id="sec-base64-length-out"><span class="header-section-number">4.3</span> Calculating the size of the output</h2>
<p>One task that we need to do is to calculate how much space we need to reserve for the output, both of the encoder and decoder. This is simple math, and can be done easily in Zig because every array has its length (its number of elements) easily accesible by consulting the <code>.len</code> property of the array.</p>
<p>For the encoder, the logic is the following: for each 3 bytes that we find in the input, 4 new bytes are created in the output. So, we take the number of bytes in the input, divide it by 3, use a ceiling function, then, we multiply the result by 4. That way, we get the total number of bytes that will be produced by the encoder in its output.</p>
<p>The <code>_calc_encode_length()</code> function below encapsulates this logic. Inside this function, we take the length of the input array, we divide it by 3, and apply a ceil operation over the result by using the <code>divCeil()</code> function from the Zig Standard Library. Lastly, we multiply the end result by 4 to get the answer we need.</p>
<p>Also, you might have notice that, if the input length is less than 3 bytes, then, the output length of the encoder is always 4 bytes. This is the case for every input with less than 3 bytes, because, as I described in <a href="#sec-base64-encoder-algo" class="quarto-xref"><span>Section 4.1.3</span></a>, the algorithm always produces enough “padding-groups” in the end result, to complete the 4 bytes window.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> std = <span class="bu">@import</span>(<span class="st">"std"</span>);</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> _calc_encode_length(input: []<span class="kw">const</span> <span class="dt">u8</span>) !<span class="dt">usize</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (input.len &lt; <span class="dv">3</span>) <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> <span class="dv">4</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> n_groups: <span class="dt">usize</span> = <span class="kw">try</span> std.math.divCeil(</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">usize</span>, input.len, <span class="dv">3</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    );</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> n_groups * <span class="dv">4</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p>Now, the logic to calculate the length of the output from the decoder is a little bit more complicated. But, it is basically just the inverse logic that we’ve used for the encoder: for each 4 bytes in the input, 3 bytes will be produced in the output of the decoder. However, this time we need to take the <code>=</code> character into account, which is always ignored by the decoder, as we described in <a href="#sec-base64-decoder-algo" class="quarto-xref"><span>Section 4.1.4</span></a>, and, in <a href="#fig-base64-algo2" class="quarto-xref">Figure&nbsp;<span>4.2</span></a>.</p>
<p>In essence, we take the length of the input and divide it by 4, then we apply a floor function on the result, then we multiply the result by 3, and then, we subtract from the result how much times the character <code>=</code> is found in the input.</p>
<p>The function <code>_calc_decode_length()</code> exposed below summarizes this logic that we described. It’s similar to the function <code>_calc_encode_length()</code>. Notice that the division part is twisted. Also notice that this time, we apply a floor operation over the output of the division, by using the <code>divFloor()</code> function (instead of a ceiling operation with <code>divCeil()</code>).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> std = <span class="bu">@import</span>(<span class="st">"std"</span>);</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> _calc_decode_length(input: []<span class="kw">const</span> <span class="dt">u8</span>) !<span class="dt">usize</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (input.len &lt; <span class="dv">4</span>) <span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> <span class="dv">3</span>;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> n_groups: <span class="dt">usize</span> = <span class="kw">try</span> std.math.divFloor(</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">usize</span>, input.len, <span class="dv">4</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    );</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> multiple_groups: <span class="dt">usize</span> = n_groups * <span class="dv">3</span>;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> i: <span class="dt">usize</span> = input.len - <span class="dv">1</span>;</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">while</span> (i &gt; <span class="dv">0</span>) : (i -= <span class="dv">1</span>) <span class="op">{</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (input[i] == <span class="ch">'='</span>) <span class="op">{</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>            multiple_groups -= <span class="dv">1</span>;</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span> <span class="kw">else</span> <span class="op">{</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>            <span class="kw">break</span>;</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> multiple_groups;</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
</section>
<section id="sec-encoder-logic" class="level2" data-number="4.4">
<h2 data-number="4.4" class="anchored" data-anchor-id="sec-encoder-logic"><span class="header-section-number">4.4</span> Building the encoder logic</h2>
<p>In this section, we can start building the logic behind the <code>encode()</code> function, which will be responsible for encoding messages into the base64 encoding system. If you are an anxious person, and you want to see now the full source code of the implementation for this base64 encoder/decoder, you can find it at the <code>ZigExamples</code> folder in the official repository of this book<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>.</p>
<section id="sec-6bit-transf" class="level3" data-number="4.4.1">
<h3 data-number="4.4.1" class="anchored" data-anchor-id="sec-6bit-transf"><span class="header-section-number">4.4.1</span> The 6-bit transformation</h3>
<p>The 6-bit transformation presented in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a> is the core part of the base64 encoder algorithm. By understanding how this transformation is made in code, the rest of the algorithm becomes much simpler to comprehend.</p>
<p>In essence, this 6-bit transformation is made with the help of bitwise operators. Bitwise operators are essential to any type of low-level operation that is done at the bit-level. For the specific case of the base64 algorithm, the operators <em>bit shift to the left</em> (<code>&lt;&lt;</code>), <em>bit shift to the right</em> (<code>&gt;&gt;</code>), and the <em>bitwise and</em> (<code>&amp;</code>) are used. They are the core solution for the 6-bit transformation.</p>
<p>There are 3 different scenarios that we need to take into account in this transformation. First, is the perfect scenario, where we have the perfect window of 3 bytes to work on. Second, we have the scenario where we have a window of only two bytes to work with. And last, we have the scenario where we have a window of one single byte.</p>
<p>In each of these 3 scenarios, the 6-bit transformation works a bit differently. To make the explanation easier, I will use the variable <code>output</code> to refer to the bytes in the output of the base64 encoder, and the variable <code>input</code> to refer to the bytes in the input of the encoder.</p>
<p>So, if you have the perfect window of 3 bytes, these are steps for the 6-bit transformation:</p>
<ol type="1">
<li><code>output[0]</code> is produced by moving the bits from <code>input[0]</code> two positions to the right.</li>
<li><code>output[1]</code> is produced by summing two components. First, take the last two bits from <code>input[0]</code>, then, move them four positions to the left. Second, move the bits from <code>input[1]</code> four positions to the right. Sum these two components.</li>
<li><code>output[2]</code> is produced by summing two components. First, take the last four bits from <code>input[1]</code>, then, move them two positions to the left. Second, move the bits from <code>input[2]</code> six positions to the right. Sum these two components.</li>
<li><code>output[3]</code> is produced by taking the last six bits from <code>input[2]</code>.</li>
</ol>
<p>This is the perfect scenario, where we have a full window of 3 bytes to work on. Just to make things as clear as possible, the <a href="#fig-encoder-bitshift" class="quarto-xref">Figure&nbsp;<span>4.3</span></a> demonstrates visually how the step 2 mentioned above works. So the 2nd byte in the <code>output</code> of the encoder, is made by taking the 1st byte (dark purple) and the 2nd byte (orange) from the input. You can see that, at the end of the process, we get a new byte that contains the last 2 bits from the 1st byte in the <code>input</code>, and the first 4 bits from the 2nd byte in the <code>input</code>.</p>
<div id="fig-encoder-bitshift" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-encoder-bitshift-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="../Figures/base64-encoder-bit-shift.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-encoder-bitshift-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4.3: How the 2nd byte in the output of the encoder is produced from the 1st byte (dark purple) and the 2nd byte (orange) of the input.
</figcaption>
</figure>
</div>
<p>On the other hand, we must be prepared for the instances where we do not have the perfect window of 3 bytes. If you have a window of 2 bytes, then, the steps 3 and 4, which produces the bytes <code>output[2]</code> and <code>output[3]</code>, change a little bit, and they become:</p>
<ul>
<li><code>output[2]</code> is produced by taking the last 4 bits from <code>input[1]</code>, then, move them two positions to the left.</li>
<li><code>output[3]</code> is the character <code>'='</code>.</li>
</ul>
<p>Finally, if you have a window of a single byte, then, the steps 2 to 4, which produces the bytes <code>output[1]</code>, <code>output[2]</code> and <code>output[3]</code> change, becoming:</p>
<ul>
<li><code>output[1]</code> is produced by taking the last two bits from <code>input[0]</code>, then, move them four positions to the left.</li>
<li><code>output[2]</code> and <code>output[3]</code> are the character <code>=</code>.</li>
</ul>
<p>If these bullet points were a bit confusing for you, you may find the <a href="#tbl-transf-6bit" class="quarto-xref">Table&nbsp;<span>4.1</span></a> more intuitive. This table unifies all this logic into a simple table. Notice that this table also provides the exact expression in Zig that creates the corresponding byte in the output.</p>
<div id="tbl-transf-6bit" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-transf-6bit-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4.1: How the 6-bit transformation translates into code in different window settings.
</figcaption>
<div aria-describedby="tbl-transf-6bit-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table">
<colgroup>
<col style="width: 30%">
<col style="width: 25%">
<col style="width: 43%">
</colgroup>
<thead>
<tr class="header">
<th>Number of bytes in the window</th>
<th>Byte index in the output</th>
<th>In code</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>3</td>
<td>0</td>
<td>input[0] &gt;&gt; 2</td>
</tr>
<tr class="even">
<td>3</td>
<td>1</td>
<td>((input[0] &amp; 0x03) &lt;&lt; 4) + (input[1] &gt;&gt; 4)</td>
</tr>
<tr class="odd">
<td>3</td>
<td>2</td>
<td>((input[1] &amp; 0x0f) &lt;&lt; 2) + (input[2] &gt;&gt; 6)</td>
</tr>
<tr class="even">
<td>3</td>
<td>3</td>
<td>input[2] &amp; 0x3f</td>
</tr>
<tr class="odd">
<td>2</td>
<td>0</td>
<td>input[0] &gt;&gt; 2</td>
</tr>
<tr class="even">
<td>2</td>
<td>1</td>
<td>((input[0] &amp; 0x03) &lt;&lt; 4) + (input[1] &gt;&gt; 4)</td>
</tr>
<tr class="odd">
<td>2</td>
<td>2</td>
<td>((input[1] &amp; 0x0f) &lt;&lt; 2)</td>
</tr>
<tr class="even">
<td>2</td>
<td>3</td>
<td>‘=’</td>
</tr>
<tr class="odd">
<td>1</td>
<td>0</td>
<td>input[0] &gt;&gt; 2</td>
</tr>
<tr class="even">
<td>1</td>
<td>1</td>
<td>((input[0] &amp; 0x03) &lt;&lt; 4)</td>
</tr>
<tr class="odd">
<td>1</td>
<td>2</td>
<td>‘=’</td>
</tr>
<tr class="even">
<td>1</td>
<td>3</td>
<td>‘=’</td>
</tr>
</tbody>
</table>
</div>
</figure>
</div>
</section>
<section id="bit-shifting-in-zig" class="level3" data-number="4.4.2">
<h3 data-number="4.4.2" class="anchored" data-anchor-id="bit-shifting-in-zig"><span class="header-section-number">4.4.2</span> Bit-shifting in Zig</h3>
<p>Bit-shifting in Zig works similarly to bit-shifting in C. All bitwise operators that exist in C are available in Zig. Here, in the base64 encoder algorithm, they are essential to produce the result we want.</p>
<p>For those who are not familiar with these operators, they are operators that operates at the bit-level of your values. This means that these operators takes the bits that form the value you have, and change them in some way. This ultimately also changes the value itself, because the binary representation of this value changes.</p>
<p>We have already seen in <a href="#fig-encoder-bitshift" class="quarto-xref">Figure&nbsp;<span>4.3</span></a> the effect produced by a bit-shift. But let’s use the first byte in the output of the base64 encoder as another example of what bit-shifting means. This is the easiest byte of the 4 bytes in the output to build. Because we only need to move the bits from the first byte in the input two positions to the right, with the <em>bit shift to the right</em> (<code>&gt;&gt;</code>) operator.</p>
<p>If we take the string “Hi” that we used in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a> as an example, the first byte in this string is “H”, which is the sequence <code>01001000</code> in binary. If we move the bits of this byte, two places to the right, we get the sequence <code>00010010</code> as result. This binary sequence is the value <code>18</code> in decimal, and also, the value <code>0x12</code> in hexadecimal. Notice that the first 6 bits of “H” were moved to the end of the byte. With this operation, we get the first byte of the output.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> std = <span class="bu">@import</span>(<span class="st">"std"</span>);</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> stdout_buffer: [<span class="dv">1024</span>]<span class="dt">u8</span> = <span class="cn">undefined</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> stdout_writer = std.fs.File.stdout().writer(&amp;stdout_buffer);</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> stdout = &amp;stdout_writer.interface;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> main() !<span class="dt">void</span> <span class="op">{</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> input = <span class="st">"Hi"</span>;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">try</span> stdout.print(<span class="st">"{d}</span><span class="sc">\n</span><span class="st">"</span>, .<span class="op">{</span>input[<span class="dv">0</span>] &gt;&gt; <span class="dv">2</span><span class="op">}</span>);</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">try</span> stdout.flush();</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>18</code></pre>
</div>
</div>
<p>If you recall <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a>, the first byte present in the output should be equivalent to the 6-bit group <code>010010</code>. Although being visually different, the sequences <code>010010</code> and <code>00010010</code> are semantically equal. They mean the same thing. They both represent the number 18 in decimal, and the value <code>0x12</code> in hexadecimal.</p>
<p>So, don’t take the “6-bit group” factor so seriously. We do not need necessarily to get a 6-bit sequence as result. As long as the meaning of the 8-bit sequence we get is the same of the 6-bit sequence, we are in the clear.</p>
</section>
<section id="selecting-specific-bits-with-the-operator" class="level3" data-number="4.4.3">
<h3 data-number="4.4.3" class="anchored" data-anchor-id="selecting-specific-bits-with-the-operator"><span class="header-section-number">4.4.3</span> Selecting specific bits with the <code>&amp;</code> operator</h3>
<p>If you comeback to <a href="#sec-6bit-transf" class="quarto-xref"><span>Section 4.4.1</span></a>, you will see that, in order to produce the second and third bytes in the output, we need to select specific bits from the first and second bytes in the input string. But how can we do that? The answer relies on the <em>bitwise and</em> (<code>&amp;</code>) operator.</p>
<p>The <a href="#fig-encoder-bitshift" class="quarto-xref">Figure&nbsp;<span>4.3</span></a> already showed you what effect this <code>&amp;</code> operator produces in the bits of its operands. But let’s make a clear description of it.</p>
<p>In summary, the <code>&amp;</code> operator performs a logical conjunction operation between the bits of its operands. In more details, the operator <code>&amp;</code> compares each bit of the first operand to the corresponding bit of the second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0 <span class="citation" data-cites="microsoftbitwiseand">(<a href="references.html#ref-microsoftbitwiseand" role="doc-biblioref">Microsoft 2021</a>)</span>.</p>
<p>So, if we apply this operator to the binary sequences <code>1000100</code> and <code>00001101</code> the result of this operation is the binary sequence <code>00000100</code>. Because only at the sixth position in both binary sequences we had a 1 value. So any position where we do not have both binary sequences setted to 1, we get a 0 bit in the resulting binary sequence.</p>
<p>We lose information about the original bit values from both sequences in this case. Because we no longer know if this 0 bit in the resulting binary sequence was produced by combining 0 with 0, or 1 with 0, or 0 with 1.</p>
<p>As an example, suppose you have the binary sequence <code>10010111</code>, which is the number 151 in decimal. How can we get a new binary sequence which contains only the third and fourth bits of this sequence?</p>
<p>We just need to combine this sequence with <code>00110000</code> (is <code>0x30</code> in hexadecimal) using the <code>&amp;</code> operator. Notice that only the third and fourth positions in this binary sequence is setted to 1. As a consequence, only the third and fourth values of both binary sequences are potentially preserved in the output. All the remaining positions are setted to zero in the output sequence, which is <code>00010000</code> (is the number 16 in decimal).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> std = <span class="bu">@import</span>(<span class="st">"std"</span>);</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> stdout_buffer: [<span class="dv">1024</span>]<span class="dt">u8</span> = <span class="cn">undefined</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> stdout_writer = std.fs.File.stdout().writer(&amp;stdout_buffer);</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> stdout = &amp;stdout_writer.interface;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> main() !<span class="dt">void</span> <span class="op">{</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> bits = <span class="bn">0b10010111</span>;</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">try</span> stdout.print(<span class="st">"{d}</span><span class="sc">\n</span><span class="st">"</span>, .<span class="op">{</span>bits &amp; <span class="bn">0b00110000</span><span class="op">}</span>);</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">try</span> stdout.flush();</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>16</code></pre>
</div>
</div>
</section>
<section id="allocating-space-for-the-output" class="level3" data-number="4.4.4">
<h3 data-number="4.4.4" class="anchored" data-anchor-id="allocating-space-for-the-output"><span class="header-section-number">4.4.4</span> Allocating space for the output</h3>
<p>As I described in <a href="01-memory.html#sec-stack" class="quarto-xref"><span>Section 3.1.4</span></a>, to store an object in the stack, this object needs to have a known and fixed length at compile-time. This is an important limitation for our base64 encoder/decoder case. Because the size of the output (from both the encoder and decoder) depends directly on the size of the input.</p>
<p>Having this in mind, we cannot know at compile time which is the size of the output for both the encoder and decoder. So, if we can’t know the size of the output at compile time, this means that we cannot store the output for both the encoder and decoder in the stack.</p>
<p>Consequently, we need to store this output on the heap, and, as I commented in <a href="01-memory.html#sec-heap" class="quarto-xref"><span>Section 3.1.5</span></a>, we can only store objects in the heap by using allocator objects. So, one of the arguments to both the <code>encode()</code> and <code>decode()</code> functions, needs to be an allocator object, because we know for sure that, at some point inside the body of these functions, we need to allocate space on the heap to store the output of these functions.</p>
<p>That is why, both the <code>encode()</code> and <code>decode()</code> functions that I present in this book, have an argument called <code>allocator</code>, which receives a allocator object as input, identified by the type <code>std.mem.Allocator</code> from the Zig Standard Library.</p>
</section>
<section id="writing-the-encode-function" class="level3" data-number="4.4.5">
<h3 data-number="4.4.5" class="anchored" data-anchor-id="writing-the-encode-function"><span class="header-section-number">4.4.5</span> Writing the <code>encode()</code> function</h3>
<p>Now that we have a basic understanding on how the bitwise operators work, and how exactly they help us to achieve the result we want to achieve. We can now encapsulate all the logic that we have described in <a href="#fig-base64-algo1" class="quarto-xref">Figure&nbsp;<span>4.1</span></a> and <a href="#tbl-transf-6bit" class="quarto-xref">Table&nbsp;<span>4.1</span></a> into a nice function that we can add to our <code>Base64</code> struct definition, that we started in <a href="#sec-base64-table" class="quarto-xref"><span>Section 4.1.2</span></a>.</p>
<p>You can find the <code>encode()</code> function below. Notice that the first argument of this function, is the <code>Base64</code> struct itself. Therefore, this argument clearly signals that this function is a method from the <code>Base64</code> struct.</p>
<p>Because the <code>encode()</code> function itself is fairly long, I intentionally omitted the <code>Base64</code> struct definition in this source code, just for brevity reasons. So, just remember that this function is a public function (or a public method) from the <code>Base64</code> struct.</p>
<p>Furthermore, this <code>encode()</code> function has two other arguments:</p>
<ol type="1">
<li><code>input</code> is the input sequence of characters that you want to encode in base64;</li>
<li><code>allocator</code> is an allocator object to use in the necessary memory allocations.</li>
</ol>
<p>I described everything you need to know about allocator objects in <a href="01-memory.html#sec-allocators" class="quarto-xref"><span>Section 3.3</span></a>. So, if you are not familiar with them, I highly recommend you to comeback to that section, and read it. By looking at the <code>encode()</code> function, you will see that we use this allocator object to allocate enough memory to store the output of the encoding process.</p>
<p>The main for loop in the function is responsible for iterating through the entire input string. In every iteration, we use a <code>count</code> variable to count how many iterations we had at the moment. When <code>count</code> reaches 3, then, we try to encode the 3 characters (or bytes) that we have accumulated in the temporary buffer object (<code>buf</code>).</p>
<p>After encoding these 3 characters and storing the result in the <code>output</code> variable, we reset the <code>count</code> variable to zero, and start to count again on the next iteration of the loop. If the loop hits the end of the string, and, the <code>count</code> variable is less than 3, then, it means that the temporary buffer contains the last 1 or 2 bytes from the input. That is why we have two <code>if</code> statements after the for loop. To deal which each possible case.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> encode(self: Base64,</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>              allocator: std.mem.Allocator,</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>              input: []<span class="kw">const</span> <span class="dt">u8</span>) ![]<span class="dt">u8</span> <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (input.len == <span class="dv">0</span>) <span class="op">{</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> <span class="st">""</span>;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> n_out = <span class="kw">try</span> _calc_encode_length(input);</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> out = <span class="kw">try</span> allocator.alloc(<span class="dt">u8</span>, n_out);</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> buf = [<span class="dv">3</span>]<span class="dt">u8</span><span class="op">{</span> <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span> <span class="op">}</span>;</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> count: <span class="dt">u8</span> = <span class="dv">0</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> iout: <span class="dt">u64</span> = <span class="dv">0</span>;</span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">for</span> (input, <span class="dv">0</span>..) |_, i| <span class="op">{</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>        buf[count] = input[i];</span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>        count += <span class="dv">1</span>;</span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (count == <span class="dv">3</span>) <span class="op">{</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>            out[iout] = self._char_at(buf[<span class="dv">0</span>] &gt;&gt; <span class="dv">2</span>);</span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a>            out[iout + <span class="dv">1</span>] = self._char_at(</span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>                ((buf[<span class="dv">0</span>] &amp; <span class="bn">0x03</span>) &lt;&lt; <span class="dv">4</span>) + (buf[<span class="dv">1</span>] &gt;&gt; <span class="dv">4</span>)</span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>            );</span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>            out[iout + <span class="dv">2</span>] = self._char_at(</span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a>                ((buf[<span class="dv">1</span>] &amp; <span class="bn">0x0f</span>) &lt;&lt; <span class="dv">2</span>) + (buf[<span class="dv">2</span>] &gt;&gt; <span class="dv">6</span>)</span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a>            );</span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a>            out[iout + <span class="dv">3</span>] = self._char_at(buf[<span class="dv">2</span>] &amp; <span class="bn">0x3f</span>);</span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a>            iout += <span class="dv">4</span>;</span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a>            count = <span class="dv">0</span>;</span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (count == <span class="dv">1</span>) <span class="op">{</span></span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a>        out[iout] = self._char_at(buf[<span class="dv">0</span>] &gt;&gt; <span class="dv">2</span>);</span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">1</span>] = self._char_at(</span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>            (buf[<span class="dv">0</span>] &amp; <span class="bn">0x03</span>) &lt;&lt; <span class="dv">4</span></span>
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a>        );</span>
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">2</span>] = <span class="ch">'='</span>;</span>
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">3</span>] = <span class="ch">'='</span>;</span>
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-40"><a href="#cb10-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-41"><a href="#cb10-41" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (count == <span class="dv">2</span>) <span class="op">{</span></span>
<span id="cb10-42"><a href="#cb10-42" aria-hidden="true" tabindex="-1"></a>        out[iout] = self._char_at(buf[<span class="dv">0</span>] &gt;&gt; <span class="dv">2</span>);</span>
<span id="cb10-43"><a href="#cb10-43" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">1</span>] = self._char_at(</span>
<span id="cb10-44"><a href="#cb10-44" aria-hidden="true" tabindex="-1"></a>            ((buf[<span class="dv">0</span>] &amp; <span class="bn">0x03</span>) &lt;&lt; <span class="dv">4</span>) + (buf[<span class="dv">1</span>] &gt;&gt; <span class="dv">4</span>)</span>
<span id="cb10-45"><a href="#cb10-45" aria-hidden="true" tabindex="-1"></a>        );</span>
<span id="cb10-46"><a href="#cb10-46" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">2</span>] = self._char_at(</span>
<span id="cb10-47"><a href="#cb10-47" aria-hidden="true" tabindex="-1"></a>            (buf[<span class="dv">1</span>] &amp; <span class="bn">0x0f</span>) &lt;&lt; <span class="dv">2</span></span>
<span id="cb10-48"><a href="#cb10-48" aria-hidden="true" tabindex="-1"></a>        );</span>
<span id="cb10-49"><a href="#cb10-49" aria-hidden="true" tabindex="-1"></a>        out[iout + <span class="dv">3</span>] = <span class="ch">'='</span>;</span>
<span id="cb10-50"><a href="#cb10-50" aria-hidden="true" tabindex="-1"></a>        iout += <span class="dv">4</span>;</span>
<span id="cb10-51"><a href="#cb10-51" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-52"><a href="#cb10-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-53"><a href="#cb10-53" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> out;</span>
<span id="cb10-54"><a href="#cb10-54" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
</section>
</section>
<section id="sec-decoder-logic" class="level2" data-number="4.5">
<h2 data-number="4.5" class="anchored" data-anchor-id="sec-decoder-logic"><span class="header-section-number">4.5</span> Building the decoder logic</h2>
<p>Now, we can focus on writing the base64 decoder logic. Remember from <a href="#fig-base64-algo2" class="quarto-xref">Figure&nbsp;<span>4.2</span></a> that, a base64 decoder does the inverse process of an encoder. So, all we need to do, is to write a <code>decode()</code> function that performs the inverse process that I exposed in <a href="#sec-encoder-logic" class="quarto-xref"><span>Section 4.4</span></a>.</p>
<section id="sec-map-base64-index" class="level3" data-number="4.5.1">
<h3 data-number="4.5.1" class="anchored" data-anchor-id="sec-map-base64-index"><span class="header-section-number">4.5.1</span> Mapping base64 characters to their indexes</h3>
<p>One thing that we need to do, in order to decode a base64-encoded message, is to calculate the index in the base64 scale of every base64 character that we encounter in the decoder input.</p>
<p>In other words, the decoder receives as input, a sequence of base64 characters. We need to translate this sequence of characters into a sequence of indexes. These indexes are the index of each character in the base64 scale. This way, we get the value/byte that was calculated in the 6-bit transformation step of the encoder process.</p>
<p>There are probably better/faster ways to calculate this, especially using a “divide and conquer” type of strategy. But for now, I am satisfied with a simple and “brute force” type of strategy. The <code>_char_index()</code> function below contains this strategy.</p>
<p>We are essentially looping through the <em>lookup table</em> with the base64 scale, and comparing the character we got with each character in the base64 scale. If these characters match, then, we return the index of this character in the base64 scale as the result.</p>
<p>Notice that, if the input character is <code>'='</code>, the function returns the index 64, which is “out of range” in the scale. But, as I described in <a href="#sec-base64-scale" class="quarto-xref"><span>Section 4.1.1</span></a>, the character <code>'='</code> does not belong to the base64 scale itself. It’s a special and meaningless character in base64.</p>
<p>Also notice that this <code>_char_index()</code> function is a method from our <code>Base64</code> struct, because of the <code>self</code> argument. Again, I have omitted the <code>Base64</code> struct definition in this example for brevity reasons.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> _char_index(self: Base64, char: <span class="dt">u8</span>) <span class="dt">u8</span> <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (char == <span class="ch">'='</span>)</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> <span class="dv">64</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> i: <span class="dt">u8</span> = <span class="dv">0</span>;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> output_index: <span class="dt">u8</span> = <span class="dv">0</span>;</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">while</span> (i &lt; <span class="dv">64</span>) : (i += <span class="dv">1</span>) <span class="op">{</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (self._char_at(i) == char)</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>            <span class="kw">break</span>;</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>        output_index += <span class="dv">1</span>;</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> output_index;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
</section>
<section id="the-6-bit-transformation" class="level3" data-number="4.5.2">
<h3 data-number="4.5.2" class="anchored" data-anchor-id="the-6-bit-transformation"><span class="header-section-number">4.5.2</span> The 6-bit transformation</h3>
<p>Once again, the core part of the algorithm is the 6-bit transformation. If we understand the necessary steps to perform this transformation, the rest of the algorithm becomes much easier.</p>
<p>First of all, before we actually go to the 6-bit transformation, we need to make sure that we use <code>_char_index()</code> to convert the sequence of base64 characters into a sequence of indexes. So the snippet below is important for the job that will be done. The result of <code>_char_index()</code> is stored in a temporary buffer, and this temporary buffer is what we are going to use in the 6-bit transformation, instead of the actual <code>input</code> object.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> (<span class="dv">0</span>..input.len) |i| <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    buf[i] = self._char_index(input[i]);</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p>Now, instead of producing 4 bytes (or 4 characters) as output per each window of 3 characters in the input, a base64 decoder produces 3 bytes (or 3 characters) as output per each window of 4 characters in the input. Once again, is the inverse process.</p>
<p>So, the steps to produce the 3 bytes in the output are:</p>
<ol type="1">
<li><code>output[0]</code> is produced by summing two components. First, move the bits from <code>buf[0]</code> two positions to the left. Second, move the bits from <code>buf[1]</code> 4 positions to the right. Then, sum these two components.</li>
<li><code>output[1]</code> is produced by summing two components. First, move the bits from <code>buf[1]</code> four positions to the left. Second, move the bits from <code>buf[2]</code> 2 positions to the right. Then, sum these two components.</li>
<li><code>output[2]</code> is produced by summing two components. First, move the bits from <code>buf[2]</code> six positions to the left. Then, you sum the result with <code>buf[3]</code>.</li>
</ol>
<p>Before we continue, let’s try to visualize how these transformations make the original bytes that we had before the encoding process. First, think back to the 6-bit transformation performed by the encoder exposed in <a href="#sec-encoder-logic" class="quarto-xref"><span>Section 4.4</span></a>. The first byte in the output of the encoder is produced by moving the bits in the first byte of the input two positions to the right.</p>
<p>If for example the first byte in the input of the encoder was the sequence <code>ABCDEFGH</code>, then, the first byte in the output of the encoder would be <code>00ABCDEF</code> (this sequence would be the first byte in the input of the decoder). Now, if the second byte in the input of the encoder was the sequence <code>IJKLMNOP</code>, then, the second byte in the encoder output would be <code>00GHIJKL</code> (as we demonstrated in <a href="#fig-encoder-bitshift" class="quarto-xref">Figure&nbsp;<span>4.3</span></a>).</p>
<p>Hence, if the sequences <code>00ABCDEF</code> and <code>00GHIJKL</code> are the first and second bytes, respectively, in the input of the decoder, the <a href="#fig-decoder-bitshift" class="quarto-xref">Figure&nbsp;<span>4.4</span></a> demonstrates visually how these two bytes are transformed into the first byte of the output of the decoder. Notice that the output byte is the sequence <code>ABCDEFGH</code>, which is the original byte from the input of the encoder.</p>
<div id="fig-decoder-bitshift" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-decoder-bitshift-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="../Figures/base64-decoder-bit-shift.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-decoder-bitshift-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4.4: How the 1st byte in the decoder output is produced from the 1st byte (dark purple) and the 2nd byte (orange) of the input
</figcaption>
</figure>
</div>
<p>The <a href="#tbl-6bit-decode" class="quarto-xref">Table&nbsp;<span>4.2</span></a> presents how the three steps described earlier translate into Zig code:</p>
<div id="tbl-6bit-decode" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-6bit-decode-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4.2: The necessary steps for the 6-transformation in the decode process.
</figcaption>
<div aria-describedby="tbl-6bit-decode-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table">
<thead>
<tr class="header">
<th>Byte index in the output</th>
<th>In code</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>(buf[0] &lt;&lt; 2) + (buf[1] &gt;&gt; 4)</td>
</tr>
<tr class="even">
<td>1</td>
<td>(buf[1] &lt;&lt; 4) + (buf[2] &gt;&gt; 2)</td>
</tr>
<tr class="odd">
<td>2</td>
<td>(buf[2] &lt;&lt; 6) + buf[3]</td>
</tr>
</tbody>
</table>
</div>
</figure>
</div>
</section>
<section id="writing-the-decode-function" class="level3" data-number="4.5.3">
<h3 data-number="4.5.3" class="anchored" data-anchor-id="writing-the-decode-function"><span class="header-section-number">4.5.3</span> Writing the <code>decode()</code> function</h3>
<p>The <code>decode()</code> function below contains the entire decoding process. We first calculate the size of the output, with <code>_calc_decode_length()</code>, then, we allocate enough memory for this output with the allocator object.</p>
<p>Three temporary variables are created: 1) <code>count</code>, to hold the window count in each iteration of the for loop; 2) <code>iout</code>, to hold the current index in the output; 3) <code>buf</code>, which is the temporary buffer that holds the base64 indexes to be converted through the 6-bit transformation.</p>
<p>Then, in each iteration of the for loop we fill the temporary buffer with the current window of bytes. When <code>count</code> hits the number 4, then, we have a full window of indexes in <code>buf</code> to be converted, and then, we apply the 6-bit transformation over the temporary buffer.</p>
<p>Notice that we check if the indexes 2 and 3 in the temporary buffer are the number 64, which, if you recall from <a href="#sec-map-base64-index" class="quarto-xref"><span>Section 4.5.1</span></a>, is when the <code>_calc_index()</code> function receives a <code>'='</code> character as input. So, if these indexes are equal to the number 64, the <code>decode()</code> function knows that it can simply ignore these indexes. They are not converted because, as I described before, the character <code>'='</code> has no meaning, despite being the end of meaningful characters in the sequence. So we can safely ignore them when they appear in the sequence.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> decode(self: Base64,</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>          allocator: std.mem.Allocator,</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>          input: []<span class="kw">const</span> <span class="dt">u8</span>) ![]<span class="dt">u8</span> <span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> (input.len == <span class="dv">0</span>) <span class="op">{</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">return</span> <span class="st">""</span>;</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> n_output = <span class="kw">try</span> _calc_decode_length(input);</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> output = <span class="kw">try</span> allocator.alloc(<span class="dt">u8</span>, n_output);</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> count: <span class="dt">u8</span> = <span class="dv">0</span>;</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> iout: <span class="dt">u64</span> = <span class="dv">0</span>;</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">var</span> buf = [<span class="dv">4</span>]<span class="dt">u8</span><span class="op">{</span> <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span> <span class="op">}</span>;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">for</span> (<span class="dv">0</span>..input.len) |i| <span class="op">{</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>        buf[count] = self._char_index(input[i]);</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>        count += <span class="dv">1</span>;</span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (count == <span class="dv">4</span>) <span class="op">{</span></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>            output[iout] = (buf[<span class="dv">0</span>] &lt;&lt; <span class="dv">2</span>) + (buf[<span class="dv">1</span>] &gt;&gt; <span class="dv">4</span>);</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>            <span class="kw">if</span> (buf[<span class="dv">2</span>] != <span class="dv">64</span>) <span class="op">{</span></span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a>                output[iout + <span class="dv">1</span>] = (buf[<span class="dv">1</span>] &lt;&lt; <span class="dv">4</span>) + (buf[<span class="dv">2</span>] &gt;&gt; <span class="dv">2</span>);</span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a>            <span class="kw">if</span> (buf[<span class="dv">3</span>] != <span class="dv">64</span>) <span class="op">{</span></span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a>                output[iout + <span class="dv">2</span>] = (buf[<span class="dv">2</span>] &lt;&lt; <span class="dv">6</span>) + buf[<span class="dv">3</span>];</span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>            iout += <span class="dv">3</span>;</span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a>            count = <span class="dv">0</span>;</span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> output;</span>
<span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
</section>
</section>
<section id="the-end-result" class="level2" data-number="4.6">
<h2 data-number="4.6" class="anchored" data-anchor-id="the-end-result"><span class="header-section-number">4.6</span> The end result</h2>
<p>Now that we have both <code>decode()</code> and <code>encode()</code> implemented. We have a fully functioning base64 encoder/decoder implemented in Zig. Here is an usage example of our <code>Base64</code> struct with the <code>encode()</code> and <code>decode()</code> methods that we have implemented.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode zig code-with-copy"><code class="sourceCode zig"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> memory_buffer: [<span class="dv">1000</span>]<span class="dt">u8</span> = <span class="cn">undefined</span>;</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> fba = std.heap.FixedBufferAllocator.init(</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    &amp;memory_buffer</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> allocator = fba.allocator();</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> text = <span class="st">"Testing some more stuff"</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> etext = <span class="st">"VGVzdGluZyBzb21lIG1vcmUgc3R1ZmY="</span>;</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> base64 = Base64.init();</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> encoded_text = <span class="kw">try</span> base64.encode(</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    allocator, text</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> decoded_text = <span class="kw">try</span> base64.decode(</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>    allocator, etext</span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a><span class="kw">try</span> stdout.print(</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>    <span class="st">"Encoded text: {s}</span><span class="sc">\n</span><span class="st">"</span>, .<span class="op">{</span>encoded_text<span class="op">}</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a><span class="kw">try</span> stdout.print(</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>    <span class="st">"Decoded text: {s}</span><span class="sc">\n</span><span class="st">"</span>, .<span class="op">{</span>decoded_text<span class="op">}</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a><span class="kw">try</span> stdout.flush();</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<pre><code>Encoded text: VGVzdGluZyBzb21lIG1vcmUgc3R1ZmY=
Decoded text: Testing some more stuff</code></pre>
<p>You can also see the full source code at once, by visiting the official repository of this book<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>. More precisely inside the <code>ZigExamples</code> folder<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>.</p>


<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list" style="display: none">
<div id="ref-microsoftbitwiseand" class="csl-entry" role="listitem">
Microsoft. 2021. <span>“Bitwise AND Operator: &amp;.”</span> Microsoft Learn. <a href="https://learn.microsoft.com/en-us/cpp/cpp/bitwise-and-operator-amp?view=msvc-170">https://learn.microsoft.com/en-us/cpp/cpp/bitwise-and-operator-amp?view=msvc-170</a>.
</div>
</div>
</section>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr>
<ol>
<li id="fn1"><p>Notice that, the character “0” is different than the actual number 0, which is simply zero in binary.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p><a href="https://github.com/pedropark99/zig-book/blob/main/ZigExamples/base64/base64_basic.zig" class="uri">https://github.com/pedropark99/zig-book/blob/main/ZigExamples/base64/base64_basic.zig</a>.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p><a href="https://github.com/pedropark99/zig-book" class="uri">https://github.com/pedropark99/zig-book</a><a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p><a href="https://github.com/pedropark99/zig-book/blob/main/ZigExamples/base64/base64_basic.zig" class="uri">https://github.com/pedropark99/zig-book/blob/main/ZigExamples/base64/base64_basic.zig</a>.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>

</main> <!-- /main -->
<script id="quarto-html-after-body" type="application/javascript">
  window.document.addEventListener("DOMContentLoaded", function (event) {
    // Ensure there is a toggle, if there isn't float one in the top right
    if (window.document.querySelector('.quarto-color-scheme-toggle') === null) {
      const a = window.document.createElement('a');
      a.classList.add('top-right');
      a.classList.add('quarto-color-scheme-toggle');
      a.href = "";
      a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; };
      const i = window.document.createElement("i");
      i.classList.add('bi');
      a.appendChild(i);
      window.document.body.appendChild(a);
    }
    setColorSchemeToggle(hasAlternateSentinel())
    const icon = "";
    const anchorJS = new window.AnchorJS();
    anchorJS.options = {
      placement: 'right',
      icon: icon
    };
    anchorJS.add('.anchored');
    const isCodeAnnotation = (el) => {
      for (const clz of el.classList) {
        if (clz.startsWith('code-annotation-')) {                     
          return true;
        }
      }
      return false;
    }
    const onCopySuccess = function(e) {
      // button target
      const button = e.trigger;
      // don't keep focus
      button.blur();
      // flash "checked"
      button.classList.add('code-copy-button-checked');
      var currentTitle = button.getAttribute("title");
      button.setAttribute("title", "Copied!");
      let tooltip;
      if (window.bootstrap) {
        button.setAttribute("data-bs-toggle", "tooltip");
        button.setAttribute("data-bs-placement", "left");
        button.setAttribute("data-bs-title", "Copied!");
        tooltip = new bootstrap.Tooltip(button, 
          { trigger: "manual", 
            customClass: "code-copy-button-tooltip",
            offset: [0, -8]});
        tooltip.show();    
      }
      setTimeout(function() {
        if (tooltip) {
          tooltip.hide();
          button.removeAttribute("data-bs-title");
          button.removeAttribute("data-bs-toggle");
          button.removeAttribute("data-bs-placement");
        }
        button.setAttribute("title", currentTitle);
        button.classList.remove('code-copy-button-checked');
      }, 1000);
      // clear code selection
      e.clearSelection();
    }
    const getTextToCopy = function(trigger) {
        const codeEl = trigger.previousElementSibling.cloneNode(true);
        for (const childEl of codeEl.children) {
          if (isCodeAnnotation(childEl)) {
            childEl.remove();
          }
        }
        return codeEl.innerText;
    }
    const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
      text: getTextToCopy
    });
    clipboard.on('success', onCopySuccess);
    if (window.document.getElementById('quarto-embedded-source-code-modal')) {
      const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
        text: getTextToCopy,
        container: window.document.getElementById('quarto-embedded-source-code-modal')
      });
      clipboardModal.on('success', onCopySuccess);
    }
      var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
      var mailtoRegex = new RegExp(/^mailto:/);
        var filterRegex = new RegExp('/' + window.location.host + '/');
      var isInternal = (href) => {
          return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
      }
      // Inspect non-navigation links and adorn them if external
     var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
      for (var i=0; i<links.length; i++) {
        const link = links[i];
        if (!isInternal(link.href)) {
          // undo the damage that might have been done by quarto-nav.js in the case of
          // links that we want to consider external
          if (link.dataset.originalHref !== undefined) {
            link.href = link.dataset.originalHref;
          }
        }
      }
    function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
      const config = {
        allowHTML: true,
        maxWidth: 500,
        delay: 100,
        arrow: false,
        appendTo: function(el) {
            return el.parentElement;
        },
        interactive: true,
        interactiveBorder: 10,
        theme: 'quarto',
        placement: 'bottom-start',
      };
      if (contentFn) {
        config.content = contentFn;
      }
      if (onTriggerFn) {
        config.onTrigger = onTriggerFn;
      }
      if (onUntriggerFn) {
        config.onUntrigger = onUntriggerFn;
      }
      window.tippy(el, config); 
    }
    const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
    for (var i=0; i<noterefs.length; i++) {
      const ref = noterefs[i];
      tippyHover(ref, function() {
        // use id or data attribute instead here
        let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
        try { href = new URL(href).hash; } catch {}
        const id = href.replace(/^#\/?/, "");
        const note = window.document.getElementById(id);
        if (note) {
          return note.innerHTML;
        } else {
          return "";
        }
      });
    }
    const xrefs = window.document.querySelectorAll('a.quarto-xref');
    const processXRef = (id, note) => {
      // Strip column container classes
      const stripColumnClz = (el) => {
        el.classList.remove("page-full", "page-columns");
        if (el.children) {
          for (const child of el.children) {
            stripColumnClz(child);
          }
        }
      }
      stripColumnClz(note)
      if (id === null || id.startsWith('sec-')) {
        // Special case sections, only their first couple elements
        const container = document.createElement("div");
        if (note.children && note.children.length > 2) {
          container.appendChild(note.children[0].cloneNode(true));
          for (let i = 1; i < note.children.length; i++) {
            const child = note.children[i];
            if (child.tagName === "P" && child.innerText === "") {
              continue;
            } else {
              container.appendChild(child.cloneNode(true));
              break;
            }
          }
          if (window.Quarto?.typesetMath) {
            window.Quarto.typesetMath(container);
          }
          return container.innerHTML
        } else {
          if (window.Quarto?.typesetMath) {
            window.Quarto.typesetMath(note);
          }
          return note.innerHTML;
        }
      } else {
        // Remove any anchor links if they are present
        const anchorLink = note.querySelector('a.anchorjs-link');
        if (anchorLink) {
          anchorLink.remove();
        }
        if (window.Quarto?.typesetMath) {
          window.Quarto.typesetMath(note);
        }
        if (note.classList.contains("callout")) {
          return note.outerHTML;
        } else {
          return note.innerHTML;
        }
      }
    }
    for (var i=0; i<xrefs.length; i++) {
      const xref = xrefs[i];
      tippyHover(xref, undefined, function(instance) {
        instance.disable();
        let url = xref.getAttribute('href');
        let hash = undefined; 
        if (url.startsWith('#')) {
          hash = url;
        } else {
          try { hash = new URL(url).hash; } catch {}
        }
        if (hash) {
          const id = hash.replace(/^#\/?/, "");
          const note = window.document.getElementById(id);
          if (note !== null) {
            try {
              const html = processXRef(id, note.cloneNode(true));
              instance.setContent(html);
            } finally {
              instance.enable();
              instance.show();
            }
          } else {
            // See if we can fetch this
            fetch(url.split('#')[0])
            .then(res => res.text())
            .then(html => {
              const parser = new DOMParser();
              const htmlDoc = parser.parseFromString(html, "text/html");
              const note = htmlDoc.getElementById(id);
              if (note !== null) {
                const html = processXRef(id, note);
                instance.setContent(html);
              } 
            }).finally(() => {
              instance.enable();
              instance.show();
            });
          }
        } else {
          // See if we can fetch a full url (with no hash to target)
          // This is a special case and we should probably do some content thinning / targeting
          fetch(url)
          .then(res => res.text())
          .then(html => {
            const parser = new DOMParser();
            const htmlDoc = parser.parseFromString(html, "text/html");
            const note = htmlDoc.querySelector('main.content');
            if (note !== null) {
              // This should only happen for chapter cross references
              // (since there is no id in the URL)
              // remove the first header
              if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
                note.children[0].remove();
              }
              const html = processXRef(null, note);
              instance.setContent(html);
            } 
          }).finally(() => {
            instance.enable();
            instance.show();
          });
        }
      }, function(instance) {
      });
    }
        let selectedAnnoteEl;
        const selectorForAnnotation = ( cell, annotation) => {
          let cellAttr = 'data-code-cell="' + cell + '"';
          let lineAttr = 'data-code-annotation="' +  annotation + '"';
          const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
          return selector;
        }
        const selectCodeLines = (annoteEl) => {
          const doc = window.document;
          const targetCell = annoteEl.getAttribute("data-target-cell");
          const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
          const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
          const lines = annoteSpan.getAttribute("data-code-lines").split(",");
          const lineIds = lines.map((line) => {
            return targetCell + "-" + line;
          })
          let top = null;
          let height = null;
          let parent = null;
          if (lineIds.length > 0) {
              //compute the position of the single el (top and bottom and make a div)
              const el = window.document.getElementById(lineIds[0]);
              top = el.offsetTop;
              height = el.offsetHeight;
              parent = el.parentElement.parentElement;
            if (lineIds.length > 1) {
              const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
              const bottom = lastEl.offsetTop + lastEl.offsetHeight;
              height = bottom - top;
            }
            if (top !== null && height !== null && parent !== null) {
              // cook up a div (if necessary) and position it 
              let div = window.document.getElementById("code-annotation-line-highlight");
              if (div === null) {
                div = window.document.createElement("div");
                div.setAttribute("id", "code-annotation-line-highlight");
                div.style.position = 'absolute';
                parent.appendChild(div);
              }
              div.style.top = top - 2 + "px";
              div.style.height = height + 4 + "px";
              div.style.left = 0;
              let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
              if (gutterDiv === null) {
                gutterDiv = window.document.createElement("div");
                gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
                gutterDiv.style.position = 'absolute';
                const codeCell = window.document.getElementById(targetCell);
                const gutter = codeCell.querySelector('.code-annotation-gutter');
                gutter.appendChild(gutterDiv);
              }
              gutterDiv.style.top = top - 2 + "px";
              gutterDiv.style.height = height + 4 + "px";
            }
            selectedAnnoteEl = annoteEl;
          }
        };
        const unselectCodeLines = () => {
          const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
          elementsIds.forEach((elId) => {
            const div = window.document.getElementById(elId);
            if (div) {
              div.remove();
            }
          });
          selectedAnnoteEl = undefined;
        };
          // Handle positioning of the toggle
      window.addEventListener(
        "resize",
        throttle(() => {
          elRect = undefined;
          if (selectedAnnoteEl) {
            selectCodeLines(selectedAnnoteEl);
          }
        }, 10)
      );
      function throttle(fn, ms) {
      let throttle = false;
      let timer;
        return (...args) => {
          if(!throttle) { // first call gets through
              fn.apply(this, args);
              throttle = true;
          } else { // all the others get throttled
              if(timer) clearTimeout(timer); // cancel #2
              timer = setTimeout(() => {
                fn.apply(this, args);
                timer = throttle = false;
              }, ms);
          }
        };
      }
        // Attach click handler to the DT
        const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
        for (const annoteDlNode of annoteDls) {
          annoteDlNode.addEventListener('click', (event) => {
            const clickedEl = event.target;
            if (clickedEl !== selectedAnnoteEl) {
              unselectCodeLines();
              const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
              if (activeEl) {
                activeEl.classList.remove('code-annotation-active');
              }
              selectCodeLines(clickedEl);
              clickedEl.classList.add('code-annotation-active');
            } else {
              // Unselect the line
              unselectCodeLines();
              clickedEl.classList.remove('code-annotation-active');
            }
          });
        }
    const findCites = (el) => {
      const parentEl = el.parentElement;
      if (parentEl) {
        const cites = parentEl.dataset.cites;
        if (cites) {
          return {
            el,
            cites: cites.split(' ')
          };
        } else {
          return findCites(el.parentElement)
        }
      } else {
        return undefined;
      }
    };
    var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
    for (var i=0; i<bibliorefs.length; i++) {
      const ref = bibliorefs[i];
      const citeInfo = findCites(ref);
      if (citeInfo) {
        tippyHover(citeInfo.el, function() {
          var popup = window.document.createElement('div');
          citeInfo.cites.forEach(function(cite) {
            var citeDiv = window.document.createElement('div');
            citeDiv.classList.add('hanging-indent');
            citeDiv.classList.add('csl-entry');
            var biblioDiv = window.document.getElementById('ref-' + cite);
            if (biblioDiv) {
              citeDiv.innerHTML = biblioDiv.innerHTML;
            }
            popup.appendChild(citeDiv);
          });
          return popup.innerHTML;
        });
      }
    }
  });
  </script>
<nav class="page-navigation">
  <div class="nav-page nav-page-previous">
      <a href="../Chapters/01-memory.html" class="pagination-link" aria-label="Memory and Allocators">
        <i class="bi bi-arrow-left-short"></i> <span class="nav-page-text"><span class="chapter-number">3</span>&nbsp; <span class="chapter-title">Memory and Allocators</span></span>
      </a>          
  </div>
  <div class="nav-page nav-page-next">
      <a href="../Chapters/02-debugging.html" class="pagination-link" aria-label="Debugging Zig applications">
        <span class="nav-page-text"><span class="chapter-number">5</span>&nbsp; <span class="chapter-title">Debugging Zig applications</span></span> <i class="bi bi-arrow-right-short"></i>
      </a>
  </div>
</nav>
</div> <!-- /content -->




</body></html>